package com.sunrise.gateway.shiro.auth;

import com.dap.utils.password.SHA3Util;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.SimpleCredentialsMatcher;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.util.ByteSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

public abstract class UserPassBaseCredentialsMatcher extends SimpleCredentialsMatcher {
    private static Logger logger = LoggerFactory.getLogger(UserPassBaseCredentialsMatcher.class);

    public abstract int getMaxRetryCount();
    public abstract Cache<String, Integer> getAuthRetryCountCache();
    public abstract String getAuthRetryCacheKey(AuthenticationToken token, AuthenticationInfo info);


    protected static boolean passCredentialsMatch(AuthenticationToken authToken, AuthenticationInfo info) {
        UsernamePasswordToken token = (UsernamePasswordToken) authToken;
        ByteSource byteSource = ((SaltedAuthenticationInfo) info).getCredentialsSalt();
        String newPass = SHA3Util.userPasswordHash(new String(token.getPassword()), new String(byteSource.getBytes()));
        return newPass.equals(info.getCredentials());
    }

    @Override
    public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
        String authRetryCacheKey = getAuthRetryCacheKey(token, info);
        if (StringUtils.isEmpty(authRetryCacheKey))
            return passCredentialsMatch(token, info);

        Cache<String, Integer> authRetryCache = getAuthRetryCountCache();

        Integer retryCount = getMaxRetryCount();
        try {
            retryCount = authRetryCache.get(authRetryCacheKey);
        } catch (Exception e) {
            logger.warn("", e);
        }

        if (retryCount == null) {
            retryCount = 1;
        } else {
            if (retryCount >= getMaxRetryCount())
                throw new ExcessiveAttemptsException();
            ++retryCount;
        }

        boolean match = false;
        try {
            match = passCredentialsMatch(token, info);
        } catch (Exception e) {
            logger.warn("", e);
        }

        try {
            if (match) {
                authRetryCache.remove(authRetryCacheKey);
            } else {
                authRetryCache.put(authRetryCacheKey, retryCount);
            }
        } catch (Exception e) {
            logger.warn("", e);
        }

        return match;
    }

}
 